﻿using System;
using System.Deployment.Application;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Plugins.Library
{
    [Serializable]
    public sealed class TextWriterProvider
    {
        private string _path;
        private TextWriterTraceListener _messages;
        private TextWriterTraceListener _output;
        private TextWriterTraceListener _exceptions;

        public TextWriterTraceListener Messages { get { return _messages; } }
        public TextWriterTraceListener Output { get { return _output; } }
        public TextWriterTraceListener Exceptions { get { return _exceptions; } }

        private ApplicationDeployment _applicationDeployment;
        public ApplicationDeployment ApplicationDeployment { get { return _applicationDeployment; } }

        private bool _useNetworkDeployment;
        public bool IsNetworkDeployed { get { return _useNetworkDeployment; } }

        [SuppressMessage("Microsoft.Performance", "CA1811")]
        public void Load(string groupName)
        {
            if (IsNetworkDeployed)
            {
                if (ApplicationDeployment.IsFirstRun)
                {
                    try
                    {
                        ApplicationDeployment.DownloadFileGroup(groupName);
                    }
                    catch (DeploymentException ex)
                    {
                        PluginLog.WriteErrorSync(ex);
                    }
                }
            }
        }

        public TextWriterProvider(bool useNetworkDeployment)
        {
            _useNetworkDeployment = useNetworkDeployment;
            if (_useNetworkDeployment)
            {
                _applicationDeployment = ApplicationDeployment.CurrentDeployment;
                _path = _applicationDeployment.DataDirectory;
            }
            else
            {
                _path = AppDomain.CurrentDomain.BaseDirectory;
            }
        }

        public string GetPath(string fileName) { return Path.Combine(_path, fileName); }

        public FileStream GetFileStream(string fileName, FileMode fileMode, FileAccess fileAccess, FileShare fileShare) { return new FileStream(GetPath(fileName), fileMode, fileAccess, fileShare); }

        private TextWriterTraceListener Register(string fileName)
        {
            return new TextWriterTraceListener(GetFileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None));
        }

        public void Run(Form form)
        {
            using (_messages = Register("application.messages.txt"))
            using (_output = Register("application.output.txt"))
            using (_exceptions = Register("application.exceptions.txt"))
            {
                try
                {
                    Update();
                    Application.Run(form);
                }
                catch (Exception ex)
                {
                    PluginLog.WriteErrorSync(ex);
                }
            }
        }
  
        private void Update()
        {
            if (IsNetworkDeployed)
            {
                try
                {
                    UpdateCheckInfo updateInfo = ApplicationDeployment.CheckForDetailedUpdate();
                    if (updateInfo != null && updateInfo.UpdateAvailable)
                    {
                        Boolean doUpdate = true;
                        if (!updateInfo.IsUpdateRequired)
                        {
                            if (!MessageBoxHelper.Accept("An update is available. Would you like to update the application now?", "Update"))
                            {
                                doUpdate = false;
                            }
                        }
                        else
                        {
                            // Display a message that the app MUST reboot. Display the minimum required version.
                            MessageBoxHelper.Info("This application has detected a mandatory update from your current version to version " + updateInfo.MinimumRequiredVersion.ToString() + ". The application will now install the update and restart.", "Update");
                        }
                        if (doUpdate)
                        {
                            try
                            {
                                ApplicationDeployment.Update();
                                MessageBoxHelper.Info("The application has been upgraded, and will now restart.", "Update");
                                Application.Restart();
                            }
                            catch (DeploymentDownloadException dde)
                            {
                                MessageBoxHelper.Info("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde, "Update");
                            }
                        }
                    }
                }
                catch (DeploymentDownloadException dde)
                {
                    PluginLog.WriteErrorSync(dde);
                }
                catch (InvalidDeploymentException ide)
                {
                    PluginLog.WriteErrorSync(ide);
                }
                catch (InvalidOperationException ioe)
                {
                    PluginLog.WriteErrorSync(ioe);
                }
            }
        }
    }

    [Serializable]
    public static class PluginProgram
    {
        private static TextWriterProvider _textWriter;
        public static TextWriterProvider Provider { get { return _textWriter; } }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        public static void Run<T>(bool networkDeployment) where T : Form, new()
        {
            _textWriter = new TextWriterProvider(networkDeployment);
            _textWriter.Run(Activator.CreateInstance<T>());
        }

        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void Run(Type type, bool networkDeployment)
        {
            _textWriter = new TextWriterProvider(networkDeployment);
            _textWriter.Run((Form)Activator.CreateInstance(type, false));
        }
    }

    public static class MessageBoxHelper
    {
        public static bool Accept(string message, string title)
        {
            return MessageBox.Show(message, title, MessageBoxButtons.OKCancel, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly) == DialogResult.OK;
        }

        public static void Info(string message, string title)
        {
            MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
        }
    }
}
